"""
错误处理器模块

提供统一的错误处理策略，包括错误分类、边界情况处理、
日志记录和用户友好的错误信息生成。
"""

from typing import Dict, List, Any, Optional, Tuple, Union
from enum import Enum
import logging
import traceback
import sys
from pathlib import Path

from .validation import ValidationError, BusinessLogicError, ConfigurationError


class ErrorSeverity(Enum):
    """错误严重程度枚举"""
    CRITICAL = "critical"    # 关键错误，无法继续执行
    ERROR = "error"         # 一般错误，可能影响功能
    WARNING = "warning"     # 警告，不影响基本功能
    INFO = "info"           # 信息提示


class ErrorCategory(Enum):
    """错误分类枚举"""
    DATA_VALIDATION = "data_validation"      # 数据验证错误
    BUSINESS_LOGIC = "business_logic"        # 业务逻辑错误
    CONFIGURATION = "configuration"         # 配置错误
    FILE_IO = "file_io"                     # 文件读写错误
    EXCEL_FORMULA = "excel_formula"         # Excel公式错误
    CALCULATION = "calculation"             # 计算错误
    SYSTEM = "system"                       # 系统错误


class ErrorHandler:
    """统一错误处理器

    功能：
    - 错误分类和优先级管理
    - 边界情况处理
    - 详细的错误信息和修复建议
    - 中文错误信息本地化
    - 日志记录
    """

    def __init__(self, strict_mode: bool = True, log_level: str = "INFO"):
        """
        初始化错误处理器

        Args:
            strict_mode: 严格模式，警告也会被视为错误
            log_level: 日志级别
        """
        self.strict_mode = strict_mode
        self.logger = self._setup_logger(log_level)

        # 错误收集器
        self.critical_errors = []  # 关键错误
        self.errors = []          # 一般错误
        self.warnings = []        # 警告
        self.infos = []           # 信息

        # 错误统计
        self.error_stats = {
            category.value: 0 for category in ErrorCategory
        }

    def handle_validation_error(self, error: ValidationError,
                              context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理数据验证错误

        Args:
            error: 验证错误实例
            context: 错误上下文信息

        Returns:
            处理结果字典
        """
        error_info = {
            'type': 'ValidationError',
            'category': ErrorCategory.DATA_VALIDATION.value,
            'severity': ErrorSeverity.ERROR.value,
            'message': str(error),
            'field': getattr(error, 'field', None),
            'value': getattr(error, 'value', None),
            'suggestions': self._get_validation_suggestions(str(error)),
            'context': context or {}
        }

        self.errors.append(error_info)
        self.error_stats[ErrorCategory.DATA_VALIDATION.value] += 1

        self.logger.error(f"数据验证错误: {error.message}")
        if error.field:
            self.logger.error(f"  字段: {error.field}")
        if error.value is not None:
            self.logger.error(f"  值: {error.value}")

        return error_info

    def handle_business_logic_error(self, error: BusinessLogicError,
                                  context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理业务逻辑错误

        Args:
            error: 业务逻辑错误实例
            context: 错误上下文信息

        Returns:
            处理结果字典
        """
        error_info = {
            'type': 'BusinessLogicError',
            'category': ErrorCategory.BUSINESS_LOGIC.value,
            'severity': ErrorSeverity.ERROR.value,
            'message': str(error),
            'code': getattr(error, 'code', None),
            'suggestions': getattr(error, 'suggestions', []),
            'context': context or {}
        }

        self.errors.append(error_info)
        self.error_stats[ErrorCategory.BUSINESS_LOGIC.value] += 1

        self.logger.error(f"业务逻辑错误: {error.message}")
        if error.code:
            self.logger.error(f"  错误代码: {error.code}")

        return error_info

    def handle_configuration_error(self, error: ConfigurationError,
                                 context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理配置错误

        Args:
            error: 配置错误实例
            context: 错误上下文信息

        Returns:
            处理结果字典
        """
        error_info = {
            'type': 'ConfigurationError',
            'category': ErrorCategory.CONFIGURATION.value,
            'severity': ErrorSeverity.CRITICAL.value,
            'message': str(error),
            'config_file': getattr(error, 'config_file', None),
            'suggestions': self._get_config_suggestions(str(error)),
            'context': context or {}
        }

        self.critical_errors.append(error_info)
        self.error_stats[ErrorCategory.CONFIGURATION.value] += 1

        self.logger.critical(f"配置错误: {error.message}")
        if error.config_file:
            self.logger.critical(f"  配置文件: {error.config_file}")

        return error_info

    def handle_file_io_error(self, error: Exception, file_path: str = None,
                           operation: str = None, context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理文件IO错误

        Args:
            error: 异常实例
            file_path: 文件路径
            operation: 操作类型（read/write/create等）
            context: 错误上下文

        Returns:
            处理结果字典
        """
        error_info = {
            'type': type(error).__name__,
            'category': ErrorCategory.FILE_IO.value,
            'severity': ErrorSeverity.ERROR.value,
            'message': self._localize_file_error(str(error), operation),
            'file_path': file_path,
            'operation': operation,
            'suggestions': self._get_file_io_suggestions(error, file_path, operation),
            'context': context or {}
        }

        self.errors.append(error_info)
        self.error_stats[ErrorCategory.FILE_IO.value] += 1

        self.logger.error(f"文件IO错误: {error_info['message']}")
        if file_path:
            self.logger.error(f"  文件路径: {file_path}")
        if operation:
            self.logger.error(f"  操作类型: {operation}")

        return error_info

    def handle_excel_formula_error(self, error_location: str, error_type: str,
                                 suggestions: List[str] = None,
                                 context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理Excel公式错误

        Args:
            error_location: 错误位置（如Sheet1!A1）
            error_type: 错误类型（如#N/A, #DIV/0!等）
            suggestions: 修复建议
            context: 错误上下文

        Returns:
            处理结果字典
        """
        error_info = {
            'type': 'ExcelFormulaError',
            'category': ErrorCategory.EXCEL_FORMULA.value,
            'severity': ErrorSeverity.ERROR.value,
            'message': self._localize_excel_error(error_type, error_location),
            'location': error_location,
            'formula_error': error_type,
            'suggestions': suggestions or self._get_excel_formula_suggestions(error_type),
            'context': context or {}
        }

        self.errors.append(error_info)
        self.error_stats[ErrorCategory.EXCEL_FORMULA.value] += 1

        self.logger.error(f"Excel公式错误: {error_info['message']}")

        return error_info

    def handle_calculation_error(self, error: Exception, calculation_type: str = None,
                               context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        处理计算错误

        Args:
            error: 异常实例
            calculation_type: 计算类型
            context: 错误上下文

        Returns:
            处理结果字典
        """
        error_info = {
            'type': type(error).__name__,
            'category': ErrorCategory.CALCULATION.value,
            'severity': ErrorSeverity.ERROR.value,
            'message': self._localize_calculation_error(str(error), calculation_type),
            'calculation_type': calculation_type,
            'suggestions': self._get_calculation_suggestions(error, calculation_type),
            'context': context or {}
        }

        self.errors.append(error_info)
        self.error_stats[ErrorCategory.CALCULATION.value] += 1

        self.logger.error(f"计算错误: {error_info['message']}")

        return error_info

    def add_warning(self, message: str, category: ErrorCategory = ErrorCategory.SYSTEM,
                   suggestions: List[str] = None, context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        添加警告信息

        Args:
            message: 警告消息
            category: 错误分类
            suggestions: 修复建议
            context: 上下文信息

        Returns:
            警告信息字典
        """
        warning_info = {
            'type': 'Warning',
            'category': category.value,
            'severity': ErrorSeverity.WARNING.value,
            'message': message,
            'suggestions': suggestions or [],
            'context': context or {}
        }

        self.warnings.append(warning_info)
        self.logger.warning(f"警告: {message}")

        return warning_info

    def add_info(self, message: str, category: ErrorCategory = ErrorCategory.SYSTEM,
                context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        添加信息提示

        Args:
            message: 信息消息
            category: 信息分类
            context: 上下文信息

        Returns:
            信息字典
        """
        info_data = {
            'type': 'Info',
            'category': category.value,
            'severity': ErrorSeverity.INFO.value,
            'message': message,
            'context': context or {}
        }

        self.infos.append(info_data)
        self.logger.info(f"信息: {message}")

        return info_data

    def handle_edge_cases(self, data: Dict[str, Any], data_type: str) -> List[Dict[str, Any]]:
        """
        处理边界情况

        Args:
            data: 待处理的数据
            data_type: 数据类型（project_info, project_roles, phases_detail等）

        Returns:
            边界情况处理结果列表
        """
        results = []

        if data_type == "project_info":
            results.extend(self._handle_project_info_edge_cases(data))
        elif data_type == "project_roles":
            results.extend(self._handle_project_roles_edge_cases(data))
        elif data_type == "phases_detail":
            results.extend(self._handle_phases_detail_edge_cases(data))

        return results

    def get_summary(self) -> Dict[str, Any]:
        """
        获取错误处理摘要

        Returns:
            错误摘要字典
        """
        total_issues = len(self.critical_errors) + len(self.errors) + len(self.warnings)

        has_blocking_issues = len(self.critical_errors) > 0 or (
            self.strict_mode and len(self.warnings) > 0
        )

        summary = {
            'total_issues': total_issues,
            'critical_errors': len(self.critical_errors),
            'errors': len(self.errors),
            'warnings': len(self.warnings),
            'infos': len(self.infos),
            'has_blocking_issues': has_blocking_issues,
            'can_proceed': not has_blocking_issues,
            'error_stats': self.error_stats.copy(),
            'all_issues': {
                'critical': self.critical_errors,
                'errors': self.errors,
                'warnings': self.warnings,
                'infos': self.infos
            }
        }

        return summary

    def clear_all(self):
        """清除所有错误记录"""
        self.critical_errors.clear()
        self.errors.clear()
        self.warnings.clear()
        self.infos.clear()

        for category in self.error_stats:
            self.error_stats[category] = 0

    # ============= 私有辅助方法 =============

    def _setup_logger(self, log_level: str) -> logging.Logger:
        """
        设置日志记录器

        Args:
            log_level: 日志级别

        Returns:
            配置好的logger实例
        """
        logger = logging.getLogger(__name__)

        if not logger.handlers:
            handler = logging.StreamHandler(sys.stdout)
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                datefmt='%Y-%m-%d %H:%M:%S'
            )
            handler.setFormatter(formatter)
            logger.addHandler(handler)

        logger.setLevel(getattr(logging, log_level.upper(), logging.INFO))
        return logger

    def _get_validation_suggestions(self, error_message: str) -> List[str]:
        """根据验证错误消息生成修复建议"""
        suggestions = []

        if "缺少必填字段" in error_message:
            suggestions.append("请检查Excel文件是否包含所有必填字段")
        elif "格式错误" in error_message:
            suggestions.append("请使用正确的日期格式YYYY-MM，例如2024-01")
        elif "未定义的角色" in error_message:
            suggestions.append("请在project_roles表中添加缺失的角色定义")
        elif "重复" in error_message:
            suggestions.append("请确保ID和名称的唯一性，删除重复项")
        elif "超过最大限制" in error_message:
            suggestions.append("请检查数值是否在合理范围内")
        else:
            suggestions.append("请检查数据的完整性和格式是否正确")

        return suggestions

    def _get_config_suggestions(self, error_message: str) -> List[str]:
        """根据配置错误消息生成修复建议"""
        suggestions = []

        if "不存在" in error_message or "找不到" in error_message:
            suggestions.append("请检查配置文件路径是否正确")
            suggestions.append("请确保配置文件存在且有读取权限")
        elif "格式错误" in error_message:
            suggestions.append("请检查配置文件的YAML格式是否正确")
            suggestions.append("请使用在线YAML验证工具检查语法")
        else:
            suggestions.append("请检查配置文件内容是否符合要求")

        return suggestions

    def _get_file_io_suggestions(self, error: Exception, file_path: str = None,
                               operation: str = None) -> List[str]:
        """根据文件IO错误生成修复建议"""
        suggestions = []

        error_type = type(error).__name__

        if error_type == "FileNotFoundError":
            suggestions.append("请确保文件路径正确且文件存在")
            suggestions.append("请检查文件是否被移动或删除")
        elif error_type == "PermissionError":
            suggestions.append("请检查文件权限，确保有读写权限")
            suggestions.append("请确保文件未被其他程序占用")
        elif error_type == "IsADirectoryError":
            suggestions.append("路径指向的是目录而不是文件，请检查路径")
        elif "excel" in str(error).lower():
            suggestions.append("请确保Excel文件格式正确且未损坏")
            suggestions.append("请关闭Excel文件后重试")
        else:
            suggestions.append("请检查文件状态和路径是否正确")

        return suggestions

    def _get_excel_formula_suggestions(self, error_type: str) -> List[str]:
        """根据Excel公式错误类型生成修复建议"""
        suggestions = []

        if error_type == "#N/A":
            suggestions.append("请检查VLOOKUP函数的查找值是否在数据源中存在")
            suggestions.append("请确保角色名称在不同表中完全一致（包括大小写和空格）")
        elif error_type == "#DIV/0!":
            suggestions.append("请检查除数是否为零")
            suggestions.append("请确保单价字段有有效的数值")
        elif error_type == "#VALUE!":
            suggestions.append("请检查公式中的数据类型是否正确")
            suggestions.append("请确保数值字段不包含文本内容")
        elif error_type == "#REF!":
            suggestions.append("请检查公式引用的单元格或工作表是否存在")
            suggestions.append("请确保工作表名称没有变更")
        else:
            suggestions.append("请检查Excel公式语法是否正确")

        return suggestions

    def _get_calculation_suggestions(self, error: Exception,
                                   calculation_type: str = None) -> List[str]:
        """根据计算错误生成修复建议"""
        suggestions = []

        error_type = type(error).__name__

        if error_type == "ZeroDivisionError":
            suggestions.append("请检查除数是否为零")
        elif error_type == "ValueError":
            suggestions.append("请检查数值格式是否正确")
            suggestions.append("请确保所有输入都是有效数字")
        elif error_type == "OverflowError":
            suggestions.append("计算结果过大，请检查输入数据的合理性")
        elif calculation_type == "人员分配":
            suggestions.append("请检查人月数和阶段时间是否合理")
            suggestions.append("请确保阶段日期范围正确")
        else:
            suggestions.append("请检查计算输入数据的有效性")

        return suggestions

    def _localize_file_error(self, error_message: str, operation: str = None) -> str:
        """本地化文件错误消息"""
        if "No such file or directory" in error_message:
            return f"文件不存在或路径错误{f'（{operation}操作）' if operation else ''}"
        elif "Permission denied" in error_message:
            return f"文件权限不足{f'（{operation}操作）' if operation else ''}"
        elif "File exists" in error_message:
            return "文件已存在"
        else:
            return f"文件操作失败{f'（{operation}操作）' if operation else ''}: {error_message}"

    def _localize_excel_error(self, error_type: str, location: str) -> str:
        """本地化Excel错误消息"""
        error_messages = {
            "#N/A": f"在位置{location}发生查找错误，找不到匹配值",
            "#DIV/0!": f"在位置{location}发生除零错误",
            "#VALUE!": f"在位置{location}发生数值类型错误",
            "#REF!": f"在位置{location}发生引用错误，公式引用无效",
            "#NAME?": f"在位置{location}发生名称错误，函数名不存在",
            "#NUM!": f"在位置{location}发生数值范围错误"
        }

        return error_messages.get(error_type, f"在位置{location}发生未知Excel错误: {error_type}")

    def _localize_calculation_error(self, error_message: str,
                                  calculation_type: str = None) -> str:
        """本地化计算错误消息"""
        prefix = f"{calculation_type}计算错误" if calculation_type else "计算错误"

        if "division by zero" in error_message.lower():
            return f"{prefix}: 除零错误"
        elif "invalid literal" in error_message.lower():
            return f"{prefix}: 数值格式错误"
        elif "overflow" in error_message.lower():
            return f"{prefix}: 数值溢出"
        else:
            return f"{prefix}: {error_message}"

    def _handle_project_info_edge_cases(self, data: Dict[str, Any]) -> List[Dict[str, Any]]:
        """处理project_info的边界情况"""
        results = []

        # 处理空字符串或None值
        for field in ['project_name', 'start_year_month', 'end_year_month']:
            if field in data and data[field] in [None, '', ' ']:
                results.append(self.add_warning(
                    f"project_info中{field}字段为空，已自动跳过",
                    ErrorCategory.DATA_VALIDATION
                ))

        return results

    def _handle_project_roles_edge_cases(self, data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """处理project_roles的边界情况"""
        results = []

        if not data:
            results.append(self.add_warning(
                "project_roles表为空，将无法进行角色验证",
                ErrorCategory.DATA_VALIDATION
            ))

        return results

    def _handle_phases_detail_edge_cases(self, data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """处理phases_detail的边界情况"""
        results = []

        if not data:
            results.append(self.add_warning(
                "phases_detail表为空，将无法生成资源计划",
                ErrorCategory.DATA_VALIDATION
            ))

        # 检查是否有非常小的人月数
        for i, phase in enumerate(data, 1):
            if 'person_months' in phase:
                try:
                    person_months = float(phase['person_months'])
                    if 0 < person_months < 0.1:
                        results.append(self.add_warning(
                            f"第{i}行人月数过小({person_months})，建议调整为至少0.1人月",
                            ErrorCategory.BUSINESS_LOGIC,
                            ["请检查人月数计算是否正确", "考虑合并小工作量的任务"]
                        ))
                except (ValueError, TypeError):
                    pass

        return results


def create_error_handler(strict_mode: bool = True, log_level: str = "INFO") -> ErrorHandler:
    """
    创建错误处理器实例

    Args:
        strict_mode: 是否启用严格模式
        log_level: 日志级别

    Returns:
        ErrorHandler实例
    """
    return ErrorHandler(strict_mode=strict_mode, log_level=log_level)


def handle_exception(error: Exception, context: Dict[str, Any] = None,
                    error_handler: ErrorHandler = None) -> Dict[str, Any]:
    """
    统一异常处理函数

    Args:
        error: 异常实例
        context: 错误上下文
        error_handler: 错误处理器实例，如果为None则创建新实例

    Returns:
        错误处理结果
    """
    if error_handler is None:
        error_handler = create_error_handler()

    # 根据异常类型分发处理
    if isinstance(error, ValidationError):
        return error_handler.handle_validation_error(error, context)
    elif isinstance(error, BusinessLogicError):
        return error_handler.handle_business_logic_error(error, context)
    elif isinstance(error, ConfigurationError):
        return error_handler.handle_configuration_error(error, context)
    elif isinstance(error, (FileNotFoundError, PermissionError, IOError)):
        return error_handler.handle_file_io_error(error, context=context)
    else:
        # 处理其他未知异常
        return error_handler.handle_calculation_error(error, "未知类型", context)